﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MinhUtils
{
    public static class NetUtil
    {
        static System.Net.WebClient WebClient
        {
            get
            {
                //if (webClient == null)
                //    webClient = new System.Net.WebClient();

                //return webClient;

                return new System.Net.WebClient();
            }
        }

        /// <summary>
        /// Check if an URL exist
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static bool Exists(string url)
        {
            //http://www.codekeep.net/snippets/cc6ab87f-1dc9-4eae-b14e-cea446767197.aspx
            try
            {
                System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);

                using (System.Net.HttpWebResponse rsp = (System.Net.HttpWebResponse)req.GetResponse())
                {
                    if (rsp.StatusCode != System.Net.HttpStatusCode.OK)
                        return false;
                }
            }
            catch
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Change a relative URL to an absolute one
        /// </summary>
        /// <param name="relativeURL">An relative URL (does not start with http://</param>
        /// <param name="absoluteURL">Absolute URL of the page that contains the relative URL</param>
        /// <returns>An absolute URL</returns>
        public static string ToAbsoluteURL(string relativeURL, string absoluteURL)
        {
            if (relativeURL.StartsWith("?")) //?page=1 (tricky)
            {
                if (absoluteURL.EndsWith("/")) //http:/abc.com/def/ (lucky case)
                {
                    return absoluteURL + relativeURL; //http://abc.com/def/?page=1
                }
                else //does not end with "/"
                {
                    if (absoluteURL.Contains("?") == false) //http://abc.com/def.php
                    {
                        return absoluteURL + relativeURL; //http://abc.com/def.php?page=1
                    }
                    else //contains "?"
                    {
                        int i = absoluteURL.LastIndexOf('?');

                        //http://abc.com/def/?page=0 OR //http://abc.com/def.php?page=0
                        if (i > absoluteURL.LastIndexOf('/'))
                        {
                            //remove from ? to end
                            absoluteURL = absoluteURL.Remove(i);

                            //add relative url
                            return absoluteURL + relativeURL;
                        }
                        else //http://abc.com/def.php?page=0/ghi.php (do they have this?)
                        {
                            return absoluteURL + relativeURL; //http://abc.com/def.php?page=0/ghi.php?page=1
                        }
                    }
                }
            }

            //http://stackoverflow.com/questions/128990/absolute-url-from-base-relative-url-in-c
            Uri baseUri = new Uri(absoluteURL);
            Uri absoluteUri = new Uri(baseUri, relativeURL);

            return absoluteUri.AbsoluteUri;
        }

        /// <summary>
        /// Downloads the requested resource as a System.String. The resource to download is specified as a System.String containing the URI.

        private static System.Net.CookieContainer cookieContainer = new System.Net.CookieContainer();
        /// </summary>
        /// <param name="pageURL">A System.String containing the URI to download.</param>
        /// <returns></returns>
        public static string DownloadContent(string pageURL)
        {
            string content = String.Empty;

            try
            {
                //using (System.Net.WebClient webClient = new System.Net.WebClient())
                //{
                //    content = webClient.DownloadString(pageURL);
                //}

                //content = new System.Net.WebClient().DownloadString(pageURL);
                content = WebClient.DownloadString(pageURL);

                //http://www.eggheadcafe.com/sample-code/csharp.NET/d342efa6-3afe-4b5d-b75a-3e2773bd0f92/use-httpwebrequest-to-read-the-contents-of-a-webpage-to-a-string.aspx
                //System.Net.WebResponse response = null;
                ////System.IO.StreamReader reader = null;
                //System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(pageURL);
                //request.CookieContainer = cookieContainer;

                //request.Method = "GET";
                //response = request.GetResponse();

                //using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream(), Encoding.UTF8))
                //{
                //    return reader.ReadToEnd();
                //}
            }
            catch (System.Net.WebException)
            {
                return String.Empty;
            }

            return content;
        }

        public static string DownloadContent(string pageURL, string postData)
        {
            //http://bytes.com/topic/net/answers/562476-how-send-https-post-request-using-c-application
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] data = encoding.GetBytes(postData);

            // Prepare web request...
            System.Net.HttpWebRequest myRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(pageURL);
            myRequest.Method = "POST";
            myRequest.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentLength = data.Length;
            System.IO.Stream newStream = myRequest.GetRequestStream();
            
            // Send the data.
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)myRequest.GetResponse();
            string pageContent = new System.IO.StreamReader(response.GetResponseStream()).ReadToEnd();

            return pageContent;
        }

        /// <summary>
        /// Load content of a page specified by the URL. If fail, keep retrying after a given interval.
        /// </summary>
        public static string TryDownloadContent(string pageURL, int sleepInterval)
        {
            string pageContent = DownloadContent(pageURL);

            while (pageContent.Equals(String.Empty))
            {
                System.Threading.Thread.Sleep(sleepInterval);
                pageContent = DownloadContent(pageURL);
            }

            return pageContent;
        }

        /// <summary>
        /// Downloads the resource with the specified URI to a local file.
        /// </summary>
        /// <param name="url">The URI from which to download data.</param>
        /// <param name="filePath">The name of the local file that is to receive the data.</param>
        public static void DownloadFile(string url, string filePath)
        {
            //// first, we need to get the exact size (in bytes) of the file we are downloading
            //System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
            //System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
            //response.Close();

            //// gets the size of the file in bytes
            //Int64 iSize = response.ContentLength;

            //// use the webclient object to download the file
            //using (System.Net.WebClient client = WebClient)
            //{
            //    // open the file at the remote URL for reading
            //    //using (System.IO.Stream streamRemote = client.OpenRead(new Uri(url)))
            //    //{
            //    System.IO.Stream streamRemote = client.OpenRead(new Uri(url));
            //        // using the FileStream object, we can write the downloaded bytes to the file system
            //        //using (System.IO.Stream streamLocal = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
            //        //{
            //        System.IO.Stream streamLocal = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
            //            // loop the stream and get the file into the byte buffer
            //            int iByteSize = 0;
            //            byte[] byteBuffer = new byte[iSize];

            //            while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
            //            {
            //                // write the bytes to the file system at the file path specified
            //                streamLocal.Write(byteBuffer, 0, iByteSize);
            //            }

            //            // clean up the file stream
            //            streamLocal.Close();
            //        //}

            //        // close the connection to the remote server
            //        streamRemote.Close();
            //    //}
            //}
            DownloadFile(url, filePath, true);
        }

        /// <summary>
        /// Downloads the resource with the specified URI to a local file.
        /// </summary>
        /// <param name="url">The URI from which to download data.</param>
        /// <param name="filePath">The name of the local file that is to receive the data.</param>
        public static void DownloadFile(string url, string filePath, bool verifyAfterDownload)
        {
            if (verifyAfterDownload)
            {
                long realFileSize = GetFileSize(url);
                long downloadedFileSize = 0;

                while (downloadedFileSize != realFileSize)
                {
                    WebClient.DownloadFile(url, filePath);
                    downloadedFileSize = new System.IO.FileInfo(filePath).Length;
                }
            }
            else
            {
                WebClient.DownloadFile(url, filePath);
            }
        }

        public static long GetFileSize(string url)
        {
            // Create a request to the file we are downloading
            System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);

            // Set default authentication for retrieving the file
            webRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
            //webRequest.Credentials = new System.Net.NetworkCredential("hitworm", "codename");

            webRequest.UserAgent = "Foo";
            webRequest.Accept = "*/*";

            // Retrieve the response from the server
            System.Net.HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse();

            // Ask the server for the file size and store it
            long fileSize = webResponse.ContentLength;

            webResponse.Close();
            webRequest.Abort();

            return fileSize;
        }

        /// <summary>
        /// Sets the maximum number of connections allowed to the specified Uri.
        /// </summary>
        public static void SetConnectionLimit(string uriString, int numberOfConnection)
        {
            System.Net.ServicePointManager.DefaultConnectionLimit = numberOfConnection;
            System.Net.ServicePointManager.FindServicePoint(new Uri(uriString)).ConnectionLimit = numberOfConnection;
        }

        public static string DecodeURL(string url)
        {
            return Uri.UnescapeDataString(url);
        }
    }
}
